#include <cassert>
#include <cmath>
#include <fstream>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include "curling/renderer.hpp"
#include "curling/opengl.hpp"
#include "curling/gui.hpp"
#include "curling/game.hpp"
#include "curling/rink.hpp"
#include "curling/stone.hpp"

namespace curling {

// vertices for a circle of radius r and s segments
void circle( double r, int s )
{
  double a = 0.0;
  double b = 2*3.1415 / static_cast<double>(s);
  for (int i=0; i<s; ++i)
  {
    glVertex2f(r*std::sin(a), r*std::cos(a));
    a += b;
  }
}

void glMaterialColor( double r, double g, double b, double a = 1.0 )
{
  GLfloat color[] = {r, g, b, a};
  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
}

void render_arrow(
  double width,
  double length,
  double segment_size )
{
  const double half_width = width / 2.0;
  const double head_width = 1.5*width;
  const double head_length = head_width * (3.0/4.0);
  const double half_head_width = head_width / 2.0;
  
  glBegin(GL_QUADS);
    glVertex2f(0.0-half_width, 0.0);
    glVertex2f(half_width, 0.0);
    glVertex2f(half_width, length);
    glVertex2f(0.0-half_width, length);
  glEnd();
  
  glBegin(GL_TRIANGLES);
    glVertex2f(0.0-half_head_width, length);
    glVertex2f(half_head_width, length);
    glVertex2f(0.0, length + head_length);
  glEnd();
}

stone_renderer_t::stone_renderer_t(
  boost::shared_ptr<stone> s,
  FMOD::System* fmod_system,
  FMOD::Sound* slide_sound )
: _stone(s),
  _fmod_system(fmod_system),
  _fmod_slide_sound(slide_sound),
  _fmod_slide_channel(NULL)
{
  int result;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_slide_sound, false, &_fmod_slide_channel);
  assert(result == FMOD_OK);
}

stone_renderer_t::~stone_renderer_t()
{
}

void stone_renderer_t::render( double t, double dt )
{
  int result;
  
  // update channel position and velocity
  FMOD_VECTOR cpos;
  cpos.x = _stone->position().x();
  cpos.y = _stone->position().y();
  cpos.z = 0.0;
  FMOD_VECTOR cvel;
  cvel.x = _stone->velocity().x();
  cvel.y = _stone->velocity().y();
  cvel.z = 0.0;
  result = _fmod_slide_channel->set3DAttributes(&cpos, &cvel);
  assert(result == FMOD_OK);
  
  // update volume
  double volume = _stone->velocity().magnitude();
  if (volume < 0.5)
  {
    volume = 0.0;
  }
  else
  {
    if (volume > 4.0)
    {
      volume = 4.0;
    }
    volume /= 4.0;
  }
  result = _fmod_slide_channel->setVolume(volume);
  assert(result == FMOD_OK);
}

/**
 * GUI listener for the renderer class.
 */
class renderer_gui_listener_t : public gui_listener
{
public:
  
  renderer_gui_listener_t( renderer* _this_ )
  : _this(_this_) {}
  virtual ~renderer_gui_listener_t() {}
  
  void quit() {}
  void play() {}
  void options() {}
  void exit_game() {}
  void exit() {}
  void pause() {}
  void resume() {}
  void player_aim( vector2d ) {}
  void player_deliver( double, double, double ) {}
  void player_begin_sweep() {}
  void player_end_sweep() {}
  void fade_complete() {}
  
  void play_title_music()
  {
    _this->play_title_music_event();
  }
  
  void stop_title_music()
  {
    _this->stop_title_music_event();
  }
  
  void start_arena_sound()
  {
    _this->start_arena_sound_event();
  }
  
  void stop_arena_sound()
  {
    _this->stop_arena_sound_event();
  }
  
  void focus_item()
  {
    _this->focus_item_event();
  }
  
  void select_item()
  {
    _this->select_item_event();
  }
  
  void game_attached( boost::shared_ptr<game> g )
  {
    _this->game_attached_event(g);
  }
  
  void game_detached( boost::shared_ptr<game> g )
  {
    _this->game_detached_event(g);
  }
  
  void camera_animation_done() {}
  void message_display_done() {}
  
private:
  
  renderer* _this;
};

/**
 * Rink listener for the renderer class.
 */
class renderer_rink_listener_t : public rink_listener_t
{
public:
  
  renderer_rink_listener_t( renderer* _this_ )
  : _this(_this_) {}
  virtual ~renderer_rink_listener_t() {}

  void stone_wall_collision(
    boost::shared_ptr<stone> s,
    double impact_velocity )
  {
  }
  
  void stone_stone_collision(
    boost::shared_ptr<stone> s1,
    boost::shared_ptr<stone> s2,
    double impact_velocity )
  {
    _this->stone_stone_collision_event(s1, s2, impact_velocity);
  }
  
private:
  
  renderer* _this;
};

renderer::renderer( boost::shared_ptr<gui> gui )
: _gui(gui),
  _fps_basetime(0.0),
  _fps_frames(0.0)
{
  _gui_listener = boost::shared_ptr<renderer_gui_listener_t>(new renderer_gui_listener_t(this));
  _gui->add_listener(_gui_listener);
  
  _font = boost::shared_ptr<texture_font_t>(new texture_font_t());
  
  // load textures

  _startMenu = boost::shared_ptr<Start_Menu_Textures>(new Start_Menu_Textures());

  glGenTextures(1, &_credits_texture);
  glBindTexture(GL_TEXTURE_2D, _credits_texture);
  assert(glfwLoadTexture2D("data/credits.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glGenTextures(1, &_seata_texture);
  glBindTexture(GL_TEXTURE_2D, _seata_texture);
  assert(glfwLoadTexture2D("data/seata.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glGenTextures(1, &_ice_texture);
  glBindTexture(GL_TEXTURE_2D, _ice_texture);
  assert(glfwLoadTexture2D("data/ice.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glGenTextures(1, &_floor_texture);
  glBindTexture(GL_TEXTURE_2D, _floor_texture);
  assert(glfwLoadTexture2D("data/floor.tga", GLFW_BUILD_MIPMAPS_BIT) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glGenTextures(1, &_marble_texture);
  glBindTexture(GL_TEXTURE_2D, _marble_texture);
  assert(glfwLoadTexture2D("data/marble.tga", GLFW_BUILD_MIPMAPS_BIT) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glGenTextures(1, &_champs_texture);
  glBindTexture(GL_TEXTURE_2D, _champs_texture);
  assert(glfwLoadTexture2D("data/champs.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glGenTextures(1, &_glow_texture);
  glBindTexture(GL_TEXTURE_2D, _glow_texture);
  assert(glfwLoadTexture2D("data/glow.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glGenTextures(1, &_title_texture);
  glBindTexture(GL_TEXTURE_2D, _title_texture);
  assert(glfwLoadTexture2D("data/title.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glGenTextures(1, &_crowd_texture);
  glBindTexture(GL_TEXTURE_2D, _crowd_texture);
  assert(glfwLoadTexture2D("data/crowd.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glGenTextures(1, &_curlingborder_texture);
  glBindTexture(GL_TEXTURE_2D, _curlingborder_texture);
  assert(glfwLoadTexture2D("data/curlingborder.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  glGenTextures(1, &_menuborder_texture);
  glBindTexture(GL_TEXTURE_2D, _menuborder_texture);
  assert(glfwLoadTexture2D("data/menuborder.tga", 0) != 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      
  //----------------------------------------------------------------------------
  // Startup sound system
  //----------------------------------------------------------------------------
  int result;
  result = FMOD::System_Create(&_fmod_system);
  assert(result == FMOD_OK);
  // init system for 100 simultaneous voices
  result = _fmod_system->init(100, FMOD_INIT_3D_RIGHTHANDED, 0);
  assert(result == FMOD_OK);
  
  result = _fmod_system->createSound("data/title.mp3", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM | FMOD_LOOP_NORMAL), 0, &_fmod_music_sound);
  if (result != FMOD_OK)
  {
    std::cerr << "could not load data/title.mp3" << std::endl;
  }
  
  // curling stone slide
  result = _fmod_system->createSound("data/slide.wav", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_3D | FMOD_LOOP_NORMAL), 0, &_fmod_slide_sound);
  assert(result == FMOD_OK);
  result = _fmod_slide_sound->set3DMinMaxDistance(2.0, 10.0);
  assert(result == FMOD_OK);
  
  result = _fmod_system->createSound("data/focus.wav", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_2D), 0, &_fmod_focus_sound);
  assert(result == FMOD_OK);
  result = _fmod_system->createSound("data/select.wav", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_2D), 0, &_fmod_select_sound);
  assert(result == FMOD_OK);
  
  result = _fmod_system->createSound("data/impact.wav", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_3D), 0, &_fmod_impact_sound);
  assert(result == FMOD_OK);
  result = _fmod_impact_sound->set3DMinMaxDistance(2.0, 10.0);
  assert(result == FMOD_OK);
  
  result = _fmod_system->createSound("data/crowd_background.wav", (FMOD_MODE)(FMOD_SOFTWARE | FMOD_2D | FMOD_LOOP_NORMAL), 0, &_fmod_crowd_background_sound);
  if (result != FMOD_OK)
  {
    std::cerr << "could not load data/crowd_background.wav" << std::endl;
  }
  _fmod_crowd_background_channel = NULL;
  
  // Setup ambient reverb, not sure how this works
  FMOD_REVERB_PROPERTIES reverb;
  result = _fmod_system->getReverbAmbientProperties(&reverb);
  assert(result == FMOD_OK);
  reverb.Instance = 0;
  reverb.Environment = 0;
  reverb.EnvSize = 35.0;
  reverb.EnvDiffusion = 0.2;
  reverb.EchoDepth = 0.1;
  result = _fmod_system->setReverbAmbientProperties(&reverb);
  assert(result == FMOD_OK);
}

renderer::~renderer()
{
  //----------------------------------------------------------------------------
  // Shut down sound system
  //----------------------------------------------------------------------------
  int result;
  result = _fmod_music_sound->release();
  assert(result == FMOD_OK);
  result = _fmod_slide_sound->release();
  assert(result == FMOD_OK);
  result = _fmod_system->close();
  assert(result == FMOD_OK);
  result = _fmod_system->release();
  assert(result == FMOD_OK);
}

void renderer::render( double t, double dt )
{
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  render_gui(t, dt);
  
  // last but not least: update sound system
  int result;
  result = _fmod_system->update();
  assert(result == FMOD_OK);
}

void renderer::render_gui( double t, double dt )
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, _gui->size().x(), 0, _gui->size().y(), -10.0, 10.0);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  update_camera(t, dt);
  render_arena(t, dt);
  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  
  if (_gui->credits_screen_visible())
  {
    render_credits_screen(t, dt);
  }
  
  //if (_gui->main_menu_visible())
  //{
  //  render_main_menu(t, dt);
  //}
  
  if (_gui->start_menu_visible())
  {
    render_start_menu(t, dt);
  }
  
  if (_gui->game_menu_visible())
  {
    render_game_menu(t, dt);
  }

   if (_gui->options_menu_visible())
  {
    render_options_menu(t, dt);
  }
  
  if (_gui->scoreboard_visible())
  {
    render_scoreboard(t, dt);
  }
  
  if (_gui->player_one_winner_visible() or _gui->player_two_winner_visible())
  {
    render_winner_screen(t, dt);
  }
  
  render_fps(t, dt);
  
  /*
   * Just a quick hack to render the number of stones left for each player.
   */
  if (_gui->current_game())
  {
    double x = 1.0;
    double y = 1.0;
    glColor3f(1.0, 0.0, 0.0);
    for (int i=0; i<_gui->current_game()->player_one_stones_left(); ++i)
    {
      glBegin(GL_QUADS);
        glVertex2f(x, y); glVertex2f(x+1.0, y);
        glVertex2f(x+1.0, y+1.0); glVertex2f(x, y+1.0);
      glEnd();
      x += 1.5;
    }
    
    x = _gui->size().x() - 2.0;
    glColor3f(0.0, 0.0, 1.0);
    for (int i=0; i<_gui->current_game()->player_two_stones_left(); ++i)
    {
      glBegin(GL_QUADS);
        glVertex2f(x, y); glVertex2f(x+1.0, y);
        glVertex2f(x+1.0, y+1.0); glVertex2f(x, y+1.0);
      glEnd();
      x -= 1.5;
    }
  }
  
  render_message(t, dt);
  
  //----------------------------------------------------------------------------
  // Fade screen
  //----------------------------------------------------------------------------
  if (_gui->screen_faded())
  {
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f(0.0, 0.0, 0.0, _gui->screen_fade());
    glBegin(GL_QUADS);
      glVertex2f(0.0, 0.0);
      glVertex2f(_gui->size().x(), 0.0);
      glVertex2f(_gui->size().x(), _gui->size().y());
      glVertex2f(0.0, _gui->size().y());
    glEnd();
    glDisable(GL_BLEND);
  }
  
  //----------------------------------------------------------------------------
  // Flash screen
  //----------------------------------------------------------------------------
  // Doesn't flash completely to white but stops at 70% opacity. Just trying to
  // get a nice smooth effect.
  if (_gui->screen_flashed())
  {
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBegin(GL_QUADS);
      glColor4f(1.0, 1.0, 1.0, min( 2.0*_gui->screen_flash(), 0.7));
      glVertex2f(0.0, 0.0);
      glColor4f(1.0, 1.0, 1.0, min( 4.0*_gui->screen_flash(), 0.7));
      glVertex2f(_gui->size().x(), 0.0);
      glColor4f(1.0, 1.0, 1.0, min( 2.0*_gui->screen_flash(), 0.7));
      glVertex2f(_gui->size().x(), _gui->size().y());
	  glColor4f(1.0, 1.0, 1.0, min( 1.0*_gui->screen_flash(), 0.7));
      glVertex2f(0.0, _gui->size().y());
    glEnd();
    glDisable(GL_BLEND);
  }
}

void renderer::render_fps( double t, double dt )
{
  if (t - _fps_basetime >= 1.0)
  {
    _fps_string = "FPS: " + boost::lexical_cast<std::string>(_fps_frames);
    _fps_basetime = t;
    _fps_frames = 0.0;
  }
  
  _fps_frames += 1.0;
  
  glColor3f(1.0, 0.0, 0.0);
  _font->render_string(_fps_string, 4.0);
}

void renderer::render_credits_screen( double t, double dt )
{
  // background
  glColor3f(0.0, 0.0, 0.0);
  glBegin(GL_QUADS);
    glVertex2f(0.0, 0.0);
    glVertex2f(_gui->size().x(), 0.0);
    glVertex2f(_gui->size().x(), _gui->size().y());
    glVertex2f(0.0, _gui->size().y());
  glEnd();
  
  glColor3f(1.0, 1.0, 1.0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _credits_texture);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex2f(_gui->size().x(), 0.0);
    glTexCoord2f(1.0, 1.0); glVertex2f(_gui->size().x(), _gui->size().y());
    glTexCoord2f(0.0, 1.0); glVertex2f(0.0, _gui->size().y());
  glEnd();
  glDisable(GL_TEXTURE_2D);
}

void renderer::render_start_menu( double t, double dt )
{
	
	double center_x = _gui->size().x() / 2.0;
	double center_y = _gui->size().y() / 2.0;

	render_menu_background(t, dt);

	//Render Team 1 box
	glPushMatrix();
	glTranslatef(center_x - 7, center_y + 20, 0.0);

	glColor4f(1.0, 1.0, 1.0, 0.8);
	_font->render_string("Team one", 1.0);

	glTranslatef(0.0, -2, 0.0);

	glColor4f(0.2, 0.2, 0.2, 0.1);
	//Adds a frame around the flag and player type.
	glBegin(GL_LINE_LOOP);
	glVertex2f(0.0, 0.0);
	glVertex2f(22.0, 0.0);
	glVertex2f(22.0, -34.0);
	glVertex2f(0.0, -34.0);
	glEnd();

	glTranslatef(1.0, -2, 0.0);
	
	_startMenu->setColor(1.0, 1.0, 1.0, 0.8);
	_startMenu->renderTexture(20, -30, Start_Menu_Textures SKIP_ENUM(::MENU_ITEMS)::SWEDEN_FLAG_ITEM, false);
    
	if (_gui->options_player_one_human_selected()) {
		glTranslatef(10.0 - _font->string_width(std::string("Human"))/20, -30.0, 0.0);
		_font->render_string("Human");
	}
	else {
		glTranslatef(10.0 - _font->string_width(std::string("AI"))/20, -30.0, 0.0);
		_font->render_string("AI");
	}

	glPopMatrix();

	//Render Team 2 box
	glPushMatrix();
	glTranslatef(center_x + 16, center_y + 20, 0.0);

	glColor4f(1.0, 1.0, 1.0, 0.8);
	_font->render_string("Team two", 1.0);

	glTranslatef(0.0, -2, 0.0);

	glColor4f(0.2, 0.2, 0.2, 0.1);

	//Adds a frame around the flag and player type.
	glBegin(GL_LINE_LOOP);
	glVertex2f(0.0, 0.0);
	glVertex2f(22.0, 0.0);
	glVertex2f(22.0, -34.0);
	glVertex2f(0.0, -34.0);
	glEnd();

	glTranslatef(1.0, -2, 0.0);
	
	_startMenu->setColor(1.0, 1.0, 1.0, 0.8);
  
	_startMenu->renderTexture(20, -30, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)CANADA_FLAG_ITEM, false);
    
	if (_gui->options_player_two_human_selected()) {
		glTranslatef(10.0 - _font->string_width(std::string("Human"))/20, -30.0, 0.0);
		_font->render_string("Human");
	}
	else {
		glTranslatef(10.0 - _font->string_width(std::string("AI"))/20, -30.0, 0.0);
		_font->render_string("AI");
	}

	glPopMatrix();


	//Render Game stones text
	glPushMatrix();
	glColor3f(1.0, 1.0, 1.0);
	glTranslatef(center_x + 15.5 - _font->string_width(std::string("Number of player stones: 4"))/20, center_y - 17.0, 0.0);
		
	_font->render_string(
	"Number of player stones: " +
	boost::lexical_cast<std::string>(_gui->options_game_stones_selected()), 5.0);
	glPopMatrix();

	//Render Game Ends text
	glPushMatrix();
	glColor3f(1.0, 1.0, 1.0);
	glTranslatef(center_x + 15.5 - _font->string_width(std::string("Regular Ends: " +
    boost::lexical_cast<std::string>(_gui->options_game_ends_selected())))/20, center_y - 19.0, 0.0);
		
	_font->render_string(
	"Regular Ends: " +
    boost::lexical_cast<std::string>(_gui->options_game_ends_selected()), 5.0);
	glPopMatrix();

	glPushMatrix();
	glTranslatef(center_x * 0.25, center_y +15, 0.0);
	//Render play item
	_startMenu->setColor(1.0, 1.0, 1.0, 1.0);

	if (_gui->start_play_focus())
	{
		_startMenu->renderTexture(8.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)PLAY_MARKED_ITEM, true);
	}
    else
    {
      _startMenu->renderTexture(8.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)PLAY_ITEM, true);
    }
    
	glPopMatrix();

	glPushMatrix();
	glTranslatef(center_x * 0.25, center_y + 12, 0.0);

	//Render options menu item
	_startMenu->setColor(1.0, 1.0, 1.0, 1.0);

	if (_gui->start_options_focus())
	{
		_startMenu->renderTexture(18.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)OPTIONS_MARKED_ITEM, true);
	}
    else
    {
      _startMenu->renderTexture(18.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)OPTIONS_ITEM, true);
    }
    
	glPopMatrix();

	glPushMatrix();
	glTranslatef(center_x * 0.25, center_y + 9, 0.0);

	//Render quit menu item
	_startMenu->setColor(1.0, 1.0, 1.0, 1.0);

	if (_gui->start_quit_focus())
	{
		_startMenu->renderTexture(8.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)QUIT_MARKED_ITEM, true);
	}
    else
    {
      _startMenu->renderTexture(8.0, 4.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)QUIT_ITEM, true);
    }
    
	glPopMatrix();

}

void renderer::render_options_menu(double t, double dt) {
	
	double center_x = _gui->size().x() / 2.0;
	double center_y = _gui->size().y() / 2.0;
  
	render_menu_background(t, dt);


	glColor3f(1.0, 1.0, 1.0);
	glPushMatrix();
	
	glTranslatef(center_x - 11, center_y * 1.5, 0.0);
	_startMenu->renderTexture(22.5, 5.0, Start_Menu_Textures:: SKIP_ENUM(MENU_ITEMS::)OPTIONS_MARKED_ITEM, true);
	glPopMatrix();

	glColor3f(0.5, 0.5, 0.5);
	

	//Render player 1 type
	glPushMatrix();
	if (_gui->options_player_one_type_focus())
		glColor3f(1, 1, 1);

	glTranslatef(center_x - 11, center_y * 1.5 - 9, 0.0);
	_font->render_string("Player One Type:  ", 5.0);

	if (_gui->options_player_one_human_selected())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(_font->string_width(std::string("Player One Type:  "))/10, 0.0 , 0.0);
	_font->render_string("Human", 5.0);

	
	if (_gui->options_player_one_ai_selected())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(_font->string_width(std::string("  Human   "))/10, 0.0, 0.0);
	_font->render_string("AI", 5.0);

	glPopMatrix();

	//Render Player 1 Team
	glPushMatrix();

	if (_gui->options_player_one_team_focus())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(center_x - 11, center_y * 1.5 - 11, 0.0);
	_font->render_string("Player 1 Team:", 5.0);

	glColor3f(0.3, 0.3, 0.3);

	glTranslatef(_font->string_width(std::string("Player 1 Team:   "))/10, 0.0 , 0.0);
	_font->render_string("Sweden", 5.0);
	
	glPopMatrix();

	//Render player 2 type
	glPushMatrix();
	if (_gui->options_player_two_type_focus())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(center_x - 11, center_y * 1.5 - 14, 0.0);
	_font->render_string("Player Two Type:  ", 5.0);

	if (_gui->options_player_two_human_selected())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(_font->string_width(std::string("Player Two Type:  "))/10, 0.0 , 0.0);
	_font->render_string("Human", 5.0);

	
	if (_gui->options_player_two_ai_selected())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(_font->string_width(std::string("  Human   "))/10, 0.0, 0.0);
	_font->render_string("AI", 5.0);

	glPopMatrix();

	//Render Player 1 Team
	glPushMatrix();

	if (_gui->options_player_two_team_focus())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(center_x - 11, center_y * 1.5 - 16, 0.0);
	_font->render_string("Player 2 Team:", 5.0);

	glColor3f(0.3, 0.3, 0.3);

	glTranslatef(_font->string_width(std::string("Player 2 Team:   "))/10, 0.0 , 0.0);
	_font->render_string("Canada", 5.0);
	
	glPopMatrix();

	//Render Game Ends
	glPushMatrix();

	if (_gui->options_game_ends_focus())
		glColor3f(1, 1, 1);
	else glColor3f(0.5, 0.5, 0.5);

	glTranslatef(center_x - 11.0, center_y * 1.5 - 19, 0.0);

  _font->render_string(
    "Regular Ends: " +
    boost::lexical_cast<std::string>(_gui->options_game_ends_selected()), 5.0);
  glPopMatrix();
  
  /* Render "Game Stones" selector */
  glPushMatrix();
  glTranslatef(center_x - 11.0, center_y * 1.5 - 21.0, 0.0);
  if (_gui->options_game_stones_focus())
  {
    glColor3f(1.0, 1.0, 1.0);
  }
  else
  {
    glColor3f(0.5, 0.5, 0.5);
  }
  _font->render_string(
    "Number of Player Stones: " +
    boost::lexical_cast<std::string>(_gui->options_game_stones_selected()), 5.0);
  glPopMatrix();

    /* Render "Back" selector */
  glPushMatrix();
  glTranslatef(center_x - 11.0, center_y * 1.5 - 24.0, 0.0);
  if (_gui->options_back_focus())
  {
    glColor3f(1.0, 1.0, 1.0);
  }
  else
  {
    glColor3f(0.5, 0.5, 0.5);
  }
  _font->render_string(
    "Back to Main Menu", 5.0);

  glPopMatrix();


}

void renderer::render_game_menu( double t, double dt )
{
  double center_x = _gui->size().x() / 2.0;
  double center_y = _gui->size().y() / 2.0;
  
  render_menu_background(t, dt);
  
  glColor3f(0.0, 0.0, 1.0);
  glPushMatrix();
  glTranslatef(center_x, center_y, 0.0);
//  glBegin(GL_QUADS);
//    glVertex2f(-10.0, -10.0);
//    glVertex2f(10.0, -10.0);
//    glVertex2f(10.0, 10.0);
//    glVertex2f(-10.0, 10.0);
//  glEnd();
  
  if (_gui->game_menu_continue_focus())
  {
    glColor3f(1.0, 1.0, 1.0);
  }
  else
  {
    glColor3f(0.5, 0.5, 0.5);
  }
  glTranslatef(-5.0, 2.0, 0.0);
  _font->render_string("Continue", 5.0);
  if (_gui->game_menu_end_focus())
  {
    glColor3f(1.0, 1.0, 1.0);
  }
  else
  {
    glColor3f(0.5, 0.5, 0.5);
  }
  glTranslatef(0.0, -4.0, 0.0);
  _font->render_string("End Game", 5.0);
  glPopMatrix();
}

void renderer::render_scoreboard( double t, double dt )
{
  double top = _gui->size().y();
  
  glPushMatrix();
    glTranslatef(1.0, top-1.0, 0.0);
  
    // red team score
    glTranslatef(0.0, -2.0, 0.0);
    render_scoreboard_team(t, dt, true);
    
    // blue team score
    glTranslatef(0.0, -2.5, 0.0);
    render_scoreboard_team(t, dt, false);
  glPopMatrix();
}

void renderer::render_scoreboard_team( double t, double dt, bool red )
{
  const double size = 2.0;
  
  GLfloat normal_color[4];
  GLfloat hilite_color[4];
  GLfloat text_color[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat disabled_text_color[4] = {0.75, 0.75, 0.75, 1.0};
  if (red)
  {
    normal_color[0] = 1.0;
    normal_color[1] = 0.0;
    normal_color[2] = 0.0;
    normal_color[3] = 0.9;
    
    hilite_color[0] = 1.0;
    hilite_color[1] = 0.5;
    hilite_color[2] = 0.5;
    hilite_color[3] = 0.9;
  }
  else
  {
    normal_color[0] = 0.0;
    normal_color[1] = 0.0;
    normal_color[2] = 1.0;
    normal_color[3] = 0.9;
    
    hilite_color[0] = 0.5;
    hilite_color[1] = 0.5;
    hilite_color[2] = 1.0;
    hilite_color[3] = 0.9;
  }
  
  glPushMatrix();
  
  // render team name
  glEnable(GL_BLEND);
  glBegin(GL_QUADS);
    glColor4fv(normal_color);
    glVertex2f(0.0, 0.0);
    glVertex2f(3.0*size, 0.0);
    glVertex2f(3.0*size, size);
    glColor4fv(hilite_color);
    glVertex2f(0.0, size);
  glEnd();
  glDisable(GL_BLEND);
  glColor4fv(text_color);
  
  glPushMatrix();
  glTranslatef(0.1, 2.0, 0.0);
  if (red)
  {
    _font->render_string("SWE", 8.0);
  }
  else
  {
    _font->render_string("CAN", 8.0);
  }
  glPopMatrix();
  
  //Added this because it crashes otherwise when starting program.
  if (!_gui->current_game())
	  return;

  // render team ends
  glTranslatef((3.0*size) + (size/4.0), 0.0, 0.0);
  for (int i=0; i <_gui->current_game()->regular_endings() ; ++i)
  {
    glEnable(GL_BLEND);
    glBegin(GL_QUADS);
      glColor4fv(normal_color);
      glVertex2f(0.0, 0.0);
      glVertex2f(size, 0.0);
      glVertex2f(size, size);
      glColor4fv(hilite_color);
      glVertex2f(0.0, size);
    glEnd();
    if (i < _gui->current_game()->current_ending())
    {
      glColor4fv(text_color);
    }
    else
    {
      glColor4fv(disabled_text_color);
    }
    glPushMatrix();
    glTranslatef(0.1, 2.0, 0.0);
    if (red)
    {
      char score[2] = {'0' + _gui->current_game()->player_one_end_score(i), 0};
      _font->render_string(score, 8.0);
    }
    else
    {
      char score[2] = {'0' + _gui->current_game()->player_two_end_score(i), 0};
      _font->render_string(score, 8.0);
    }
    glPopMatrix();
    glTranslatef(size + (size/4.0), 0.0, 0.0);
  }
  
  // render team total score
  glEnable(GL_BLEND);
  glBegin(GL_QUADS);
    glColor4fv(normal_color);
    glVertex2f(0.0, 0.0);
    glVertex2f(1.5*size, 0.0);
    glVertex2f(1.5*size, size);
    glColor4fv(hilite_color);
    glVertex2f(0.0, size);
  glEnd();
  glColor4fv(text_color);
  glPushMatrix();
  glTranslatef(0.1, 2.0, 0.0);
  if (red)
  {
    _font->render_string(
      boost::lexical_cast<std::string>(_gui->current_game()->player_one_score()), 8.0);
  }
  else
  {
    _font->render_string(
      boost::lexical_cast<std::string>(_gui->current_game()->player_two_score()), 8.0);
  }
  glPopMatrix();
  
  glPopMatrix();
}

void renderer::render_message( double t, double dt )
{
  if (_gui->message_time() > -1.0)
  {
    if (_gui->message_time() < 0.0)
    {
      glColor4f(0.0, 0.0, 0.0, 1.0 + _gui->message_time());
    }
    else
    {
      glColor4f(0.0, 0.0, 0.0, 1.0);
    }
    
    glPushMatrix();
    glTranslatef(
      (_gui->size().x() / 2.0) ,//- (_font->string_width(_gui->message_displayed()) / 2.0),
      _gui->size().y() / 2.0,
      0.0);
    _font->render_string(_gui->message_displayed(), 1.0);
    glPopMatrix();
  }
}

void renderer::render_winner_screen( double t, double dt )
{
	float center_x = _gui->size().x() / 2.0;
	float center_y = _gui->size().y() / 2.0;
  
	render_menu_background(t, dt);
	glPushMatrix();
	
	unsigned int winnerID;
	unsigned int trophyID;
    if (_gui->player_one_winner_visible())
    {

	
		winnerID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TEAM_ONE_WINS_ITEM;
		trophyID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TEAM_ONE_TROPHY_ITEM; 


    } else if (_gui->player_two_winner_visible())
    {
		winnerID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TEAM_TWO_WINS_ITEM;
		trophyID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TEAM_TWO_TROPHY_ITEM; 
    }

    // tie
    if (_gui->player_one_winner_visible() and _gui->player_two_winner_visible())
    {
		winnerID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TIE_ITEM;
		trophyID = Start_Menu_Textures::SKIP_ENUM(MENU_ITEMS::)TIE_TROPHY; 
    }

	glTranslatef(center_x-12, center_y + center_y/2, 0.0);
		
	_startMenu->setColor(1.0, 1.0, 1.0, 1.0);
	_startMenu->renderTexture(24, -14, winnerID, false);

	glTranslatef(-3.5, -13, 0.0);
	_startMenu->renderTexture(42, -42, trophyID, false);

	glPopMatrix();

	/* Render "Back" selector */
	/*  glPushMatrix();
	  glTranslatef(center_x - 11.0, center_y * 1.5 - 24.0, 0.0);
	  if (_gui->options_back_focus())
	  {
		glColor3f(1.0, 1.0, 1.0);
	  }
	  else
	  {
		glColor3f(0.5, 0.5, 0.5);
	  }
	  _font->render_string(
		"Back to Main Menu", 5.0);

	  glPopMatrix();*/
}

void renderer::render_powermeter( double t, double dt )
{
  assert(_gui->current_game());
  
  glDisable(GL_LIGHTING);

  glPushMatrix();
  glTranslatef(0.0, _gui->current_game()->rink_played()->hack() + 1.0, 0.0);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  // render shadow arrow
  double shd = (3.1415/2.0)-(3.1415*0.25*_gui->shadow_arrow_direction());
  double shx = std::cos(shd)*2.0*_gui->shadow_arrow_power();
  double shy = std::sin(shd)*2.0*_gui->shadow_arrow_power();
  double smd = (3.1415/2.0)-((3.1415*0.25*(_gui->shadow_arrow_direction()+(_gui->shadow_arrow_spin()*0.5))));
  double smx = std::cos(smd)*_gui->shadow_arrow_power()*0.75;
  double smy = std::sin(smd)*_gui->shadow_arrow_power()*0.75;
  glColor4f(0.0, 0.0, 0.0, 0.5);
  glBegin(GL_QUADS);
    glVertex2f(-0.1, 0.0);
    glVertex2f(0.1, 0.0);
    glVertex2f(smx+0.1, smy);
    glVertex2f(smx-0.1, smy);
    glVertex2f(smx-0.1, smy);
    glVertex2f(smx+0.1, smy);
    glVertex2f(shx+0.1, shy);
    glVertex2f(shx-0.1, shy);
  glEnd();
  
  // render shot arrow
  double hd = (3.1415/2.0)-(3.1415*0.25*_gui->shot_arrow_direction());
  double hx = std::cos(hd)*2.0*_gui->shot_arrow_power();
  double hy = std::sin(hd)*2.0*_gui->shot_arrow_power();
  double md = (3.1415/2.0)-((3.1415*0.25*(_gui->shot_arrow_direction()+(_gui->shot_arrow_spin()*0.5))));
  double mx = std::cos(md)*_gui->shot_arrow_power()*0.75;
  double my = std::sin(md)*_gui->shot_arrow_power()*0.75;
  glColor4f(1.0, 0.0, 0.0, 0.8);
  glBegin(GL_QUADS);
    glVertex2f(-0.1, 0.0);
    glVertex2f(0.1, 0.0);
    glVertex2f(mx+0.1, my);
    glVertex2f(mx-0.1, my);
    glVertex2f(mx-0.1, my);
    glVertex2f(mx+0.1, my);
    glVertex2f(hx+0.1, hy);
    glVertex2f(hx-0.1, hy);
  glEnd();
  glPopMatrix();

  glDisable(GL_BLEND);
  glEnable(GL_LIGHTING);
}

void renderer::update_camera( double t, double dt )
{
  boost::shared_ptr<camera> cam = _gui->current_camera();
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(cam->fov(), cam->aspect(), 0.1, 100.0);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
  gluLookAt(cam->position().x(), cam->position().y(), cam->position().z(),
            cam->target().x(), cam->target().y(), cam->target().z(),
            cam->up().x(), cam->up().y(), cam->up().z());
            
  // update listener position
  // we don't care about listener velocity so NULL is passed
  int result;
  FMOD_VECTOR lpos;
  lpos.x = cam->position().x();
  lpos.y = cam->position().y();
  lpos.z = cam->position().z();
  FMOD_VECTOR lfwd;
  lfwd.x = cam->direction().x();
  lfwd.y = cam->direction().y();
  lfwd.z = cam->direction().z();
  FMOD_VECTOR lup;
  lup.x = cam->up().x();
  lup.y = cam->up().y();
  lup.z = cam->up().z();
  result = _fmod_system->set3DListenerAttributes(0, &lpos, NULL, &lfwd, &lup);
  assert(result == FMOD_OK);
}

void renderer::render_arena( double t, double dt )
{
  glEnable(GL_LIGHTING);
  
  // setup ambient light
  GLfloat ambient_light[] = {0.4, 0.4, 0.4, 1.0};
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient_light);
  
  // setup main light as a directional light source
  glEnable(GL_LIGHT0);
  GLfloat main_light_diffuse[] = {0.8, 0.8, 0.8, 1.0};
  glLightfv(GL_LIGHT0, GL_DIFFUSE, main_light_diffuse);
  GLfloat main_light_position[] = {0.0, 0.0, 1.0, 0.0};//w=0.0 => directional
  glLightfv(GL_LIGHT0, GL_POSITION, main_light_position);
  
  // extra positional light source for increased feel =)
  glEnable(GL_LIGHT1);
  GLfloat extra_light_diffuse[] = {0.3, 0.3, 0.3, 1.0};
  glLightfv(GL_LIGHT1, GL_DIFFUSE, extra_light_diffuse);
  GLfloat extra_light_position[] = {0.0, 25.0, 20.0, 1.0};
  glLightfv(GL_LIGHT1, GL_POSITION, extra_light_position);
  
  render_floor(t, dt);
  
  // render leftmost rink
  glPushMatrix();
  glTranslatef(-9.5, -_gui->background_rink()->length() / 2.0, 0.0);
  render_rink(_gui->background_rink(), t, dt);
  glPopMatrix();
  
  // render rink being played
  glPushMatrix();
  glTranslatef(-3.0, -_gui->background_rink()->length() / 2.0, 0.0);
  if (_gui->current_game())
  {
    render_rink(_gui->current_game()->rink_played(), t, dt);
  }
  else
  {
    render_rink(_gui->background_rink(), t, dt);
  }
  glPopMatrix();
  
  // render right rink
  glPushMatrix();
  glTranslatef(3.0, -_gui->background_rink()->length() / 2.0, 0.0);
  render_rink(_gui->background_rink(), t, dt);
  glPopMatrix();
  
  // render rightmost rink
  glPushMatrix();
  glTranslatef(9.5, -_gui->background_rink()->length() / 2.0, 0.0);
  render_rink(_gui->background_rink(), t, dt);
  glPopMatrix();
  
  // render characters
  // disabled since this feature has been cut
  //glDisable(GL_LIGHTING);
  //render_characters(t, dt);
  //glEnable(GL_LIGHTING);
  
  //  setup separate light for spectators using positional light source
  glDisable(GL_LIGHT1);
  GLfloat external_light_diffuse[] = {0.6, 0.6, 0.8, 1.0};
  glLightfv(GL_LIGHT0, GL_DIFFUSE, external_light_diffuse);
  GLfloat external_light_position[] = {0.0, 25.0, 20.0, 1.0};
  glLightfv(GL_LIGHT0, GL_POSITION, external_light_position);
  
  glEnable(GL_DEPTH_TEST);
  render_sections(t, dt);
  glDisable(GL_DEPTH_TEST);
  
  render_ceiling(t, dt);
  
  glDisable(GL_LIGHT0);
  glDisable(GL_LIGHTING);
}

/**
 * Render a rink
 */
void renderer::render_rink( boost::shared_ptr<rink> rink, double t, double dt )
{
  glNormal3f(0.0, 0.0, 1.0);
  
  //----------------------------------------------------------------------------
  // Render Ice Surface
  //----------------------------------------------------------------------------
  glMaterialColor(1.0, 1.0, 1.0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _ice_texture);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-rink->width() / 2.0, 0.0, 0.0);
    glTexCoord2f(rink->width(), 0.0); glVertex3f(rink->width() / 2.0, 0.0, 0.0);
    glTexCoord2f(rink->width(), rink->length()); glVertex3f(rink->width() / 2.0, rink->length(), 0.0);
    glTexCoord2f(0.0, rink->length()); glVertex3f(-rink->width() / 2.0, rink->length(), 0.0);
  glEnd();
  glDisable(GL_TEXTURE_2D);
  
  //----------------------------------------------------------------------------
  // Render Circles
  //----------------------------------------------------------------------------
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
  const double r0 = rink->circle0_radius();
  const double r1 = rink->circle1_radius();
  const double r2 = rink->circle2_radius();
  const double r3 = rink->circle3_radius();
  const double i_inc = (2.0*M_PI)/40.0;
  glPushMatrix();
    glTranslatef(0.0, rink->circle(), 0.0);
    // red circle
    glMaterialColor(1.0, 0.0, 0.0, 0.8);
    glBegin(GL_TRIANGLE_STRIP);
      for (double i=0.0; i<=2.0*M_PI; i+=i_inc)
      {
        glVertex2f(r2*std::cos(i), r2*std::sin(i));
        glVertex2f(r3*std::cos(i+(i_inc*0.5)), r3*std::sin(i+(i_inc*0.5)));
      }
    glEnd();
    // blue cirlce
    glMaterialColor(0.0, 0.0, 1.0, 0.8);
    glBegin(GL_TRIANGLE_STRIP);
      for (double i=0.0; i<=2.0*M_PI; i+=i_inc)
      {
        glVertex2f(r0*std::cos(i), r0*std::sin(i));
        glVertex2f(r1*std::cos(i+(i_inc*0.5)), r1*std::sin(i+(i_inc*0.5)));
      }
    glEnd();
  glPopMatrix();
  
  glPushMatrix();
    glTranslatef(0.0, rink->length()-rink->circle(), 0.0);
    // red circle
    glMaterialColor(1.0, 0.0, 0.0, 0.8);
    glBegin(GL_TRIANGLE_STRIP);
      for (double i=0.0; i<=2.0*M_PI; i+=i_inc)
      {
        glVertex2f(r2*std::cos(i), r2*std::sin(i));
        glVertex2f(r3*std::cos(i+(i_inc*0.5)), r3*std::sin(i+(i_inc*0.5)));
      }
    glEnd();
    // blue cirlce
    glMaterialColor(0.0, 0.0, 1.0, 0.8);
    glBegin(GL_TRIANGLE_STRIP);
      for (double i=0.0; i<=2.0*M_PI; i+=i_inc)
      {
        glVertex2f(r0*std::cos(i), r0*std::sin(i));
        glVertex2f(r1*std::cos(i+(i_inc*0.5)), r1*std::sin(i+(i_inc*0.5)));
      }
    glEnd();
  glPopMatrix();
  glDisable(GL_BLEND);
  
  //----------------------------------------------------------------------------
  // Render Hacks
  //----------------------------------------------------------------------------
  glMaterialColor(0.0, 0.0, 0.0);
  
  glPushMatrix();
    glTranslatef(0.0, rink->hack(), 0.0);
    glBegin(GL_QUADS);
      glVertex2f(-0.2, -0.1);
      glVertex2f(0.2, -0.1);
      glVertex2f(0.2, 0.1);
      glVertex2f(-0.2, 0.1);
    glEnd();
  glPopMatrix();

  glPushMatrix();
    glTranslatef(0.0, rink->length()-rink->hack(), 0.0);
    glBegin(GL_QUADS);
      glVertex2f(-0.2, -0.1);
      glVertex2f(0.2, -0.1);
      glVertex2f(0.2, 0.1);
      glVertex2f(-0.2, 0.1);
    glEnd();
  glPopMatrix();
  
  //----------------------------------------------------------------------------
  // Render Back Lines
  //----------------------------------------------------------------------------
  glMaterialColor(0.0, 0.0, 1.0, 0.5);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->back_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->length()-rink->back_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  glDisable(GL_BLEND);
  
  //----------------------------------------------------------------------------
  // Render Tee Lines
  //----------------------------------------------------------------------------
  glMaterialColor(0.0, 0.0, 0.0, 0.5);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->tee_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->length()-rink->tee_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  glDisable(GL_BLEND);
  
  //----------------------------------------------------------------------------
  // Render Hog Lines
  //----------------------------------------------------------------------------
  glMaterialColor(1.0, 0.0, 0.0, 0.5);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->hog_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  
  glPushMatrix();
    glTranslatef(-rink->width()/2.0, rink->length()-rink->hog_line(), 0.0);
    glBegin(GL_LINES);
      glVertex2f(0.0, 0.0);
      glVertex2f(rink->width(), 0.0);
    glEnd();
  glPopMatrix();
  glDisable(GL_BLEND);
  
  //----------------------------------------------------------------------------
  // Render Center Line
  //----------------------------------------------------------------------------
  glMaterialColor(0.0, 0.0, 0.0, 0.5);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBegin(GL_LINES);
    glVertex2f(0.0, 0.0);
    glVertex2f(0.0, rink->length());
  glEnd();
  glDisable(GL_BLEND);
  
  //----------------------------------------------------------------------------
  // Since the power-meter is displayed on-ice, it has to be rendered from here.
  //----------------------------------------------------------------------------
  if (_gui->powermeter_visible())
  {
    render_powermeter(t, dt);
  }
  
  //----------------------------------------------------------------------------
  // Render sides
  //----------------------------------------------------------------------------
  glDisable(GL_LIGHTING);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBegin(GL_QUADS);
    // north shadows
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-rink->width()/2.0, rink->length()-0.2);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+rink->width()/2.0, rink->length()-0.2);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+rink->width()/2.0, rink->length()+0.2);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-rink->width()/2.0, rink->length()+0.2);
    
    // east
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+(rink->width()/2.0)-0.2, rink->length());
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+(rink->width()/2.0)-0.2, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+(rink->width()/2.0)+0.2, 0.0);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+(rink->width()/2.0)+0.2, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, rink->length());
    
    // west
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-(rink->width()/2.0)+0.2, rink->length());
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-(rink->width()/2.0)+0.2, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-(rink->width()/2.0)-0.2, 0.0);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-(rink->width()/2.0)-0.2, rink->length());
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, rink->length());
    
    // south
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-rink->width()/2.0, -0.2);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+rink->width()/2.0, -0.2);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0-rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0+rink->width()/2.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0+rink->width()/2.0, 0.2);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0-rink->width()/2.0, 0.2);
  glEnd();
  glDisable(GL_BLEND);
  glEnable(GL_LIGHTING);
  
  // north wall
  glPushMatrix();
    glTranslatef(0.0-rink->width()/2.0, rink->length(), 0.0);
    render_rink_wall(t, dt, rink->width());
  glPopMatrix();
  // east wall
  glPushMatrix();
    glTranslatef(rink->width()/2.0, rink->length(), 0.0);
    glRotatef(-90.0, 0.0, 0.0, 1.0);
    render_rink_wall(t, dt, rink->length());
  glPopMatrix();
  // south wall
  glPushMatrix();
    glTranslatef(rink->width()/2.0, 0.0, 0.0);
    glRotatef(-180.0, 0.0, 0.0, 1.0);
    render_rink_wall(t, dt, rink->width());
  glPopMatrix();
  // west wall
  glPushMatrix();
    glTranslatef(0.0-rink->width()/2.0, 0.0, 0.0);
    glRotatef(-270.0, 0.0, 0.0, 1.0);
    render_rink_wall(t, dt, rink->length());
  glPopMatrix();
  
  //----------------------------------------------------------------------------
  // Render Stones
  //----------------------------------------------------------------------------
  for (rink::stone_iterator i = rink->begin_stones(); i != rink->end_stones(); ++i)
  {
    render_stone(*i, t, dt);
    boost::shared_ptr<stone_renderer_t> sr = _stone_renderers[*i];
    if (not sr)
    {
      sr = boost::shared_ptr<stone_renderer_t>(new stone_renderer_t(*i, _fmod_system, _fmod_slide_sound));
      _stone_renderers[*i] = sr;
    }
    sr->render(t, dt);
  }
}

void renderer::render_rink_wall( double t, double dt, double length )
{
  const double height = 0.15;
  const double width = 0.05;
  
  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  
  glMaterialColor(0.5, 0.5, 1.0);
  
  // front side
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(length, 0.0, 0.0);
    glVertex3f(length, 0.0, height);
    glVertex3f(0.0, 0.0, height);
  glEnd();
  
  // back side
  glNormal3f(0.0, 1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(length+width, width, 0.0);
    glVertex3f(0.0-width, width, 0.0);
    glVertex3f(0.0-width, width, height);
    glVertex3f(length+width, width, height);
  glEnd();
  
  // top
  glNormal3f(0.0, 0.0, 1.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 0.0, height);
    glVertex3f(length, 0.0, height);
    glVertex3f(length+width, width, height);
    glVertex3f(0.0-width, width, height);
  glEnd();
  
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_CULL_FACE);
}

void renderer::render_stone( boost::shared_ptr<stone> stone, double t, double dt )
{
  if (!stone->in_play()) return;
  
  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  
  glPushMatrix();
  glTranslatef(stone->position().x(), stone->position().y(), 0.00);
  glRotatef((stone->rotation()/(2.0*3.1415))*360.0, 0.0, 0.0, 1.0);
  
  const double r1 = stone->radius();
  const double h1 = stone->height()*0.8;
  const double h2 = stone->height()*0.1;
  const double r2 = r1*0.8;
  //const double s1 = (2.0*3.1415) / 20.0;
  const double s2 = (2.0*M_PI) / 20.0;
  
  //----------------------------------------------------------------------------
  // Reflection of lower body in ice.
  //----------------------------------------------------------------------------
  glPushMatrix();
  glDisable(GL_DEPTH_TEST);
  glRotatef(180.0, 1.0, 0.0, 0.0);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glMaterialColor(0.7, 0.7, 0.7, 0.3);
  // main body
  glBegin(GL_TRIANGLE_STRIP);
    for (double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      glNormal3f(std::cos(i), std::sin(i), 0.6);
      glVertex3f(r1*std::cos(i), r1*std::sin(i), h2+h1);
      
      glNormal3f(std::cos(i+(0.5*s2)), std::sin(i+(0.5*s2)), 0.6);
      glVertex3f(r1*std::cos(i+(0.5*s2)), r1*std::sin(i+(0.5*s2)), h2);
    }
  glEnd();

  // lower rounded edge
  glBegin(GL_TRIANGLE_STRIP);
    for (double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      const double x1 = r1*std::cos(i);
      const double y1 = r1*std::sin(i);
      const double x2 = r2*std::cos(i+(0.5*s2));
      const double y2 = r2*std::sin(i+(0.5*s2));
      glNormal3f(x1, y1, 0.8); glVertex3f(x1, y1, h2);
      glNormal3f(x1, y1, 0.6); glVertex3f(x2, y2, 0.0);
    }
  glEnd();
  glDisable(GL_BLEND);
  glPopMatrix();

  //----------------------------------------------------------------------------
  // Point Tag Glow
  //----------------------------------------------------------------------------
  if (stone->tagged_as_point())
  {
    switch (stone->color())
    {
    case color_red:
      glColor4f(1.0, 0.0, 0.0, 0.8+(sin(t*2.0)*0.2));
      break;
  
    case color_blue:
      glColor4f(0.0, 0.0, 1.0, 0.8+(sin(t*2.0)*0.2));
      break;
  
    default:
      assert(false);
      break;
    }
  
    glDisable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, _glow_texture);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBegin(GL_QUADS);
      glTexCoord2f(0.0, 0.0);
      glVertex2f(0.0-(r1*1.5), 0.0-(r1*1.5));
      glTexCoord2f(1.0, 0.0);
      glVertex2f(0.0+(r1*1.5), 0.0-(r1*1.5));
      glTexCoord2f(1.0, 1.0);
      glVertex2f(0.0+(r1*1.5), 0.0+(r1*1.5));
      glTexCoord2f(0.0, 1.0);
      glVertex2f(0.0-(r1*1.5), 0.0+(r1*1.5));
    glEnd();
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_LIGHTING);
  }
  
  //----------------------------------------------------------------------------
  // Actual stone
  //----------------------------------------------------------------------------
  glEnable(GL_DEPTH_TEST);
  glMaterialColor(1.0, 1.0, 1.0);
  
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _marble_texture);
  
  // main body
  glBegin(GL_TRIANGLE_STRIP);
    for (double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      glNormal3f(std::cos(i), std::sin(i), 0.6);
      glTexCoord2f(i/(2.0*M_PI), 0.8);
      glVertex3f(r1*std::cos(i), r1*std::sin(i), h2+h1);
      
      glNormal3f(std::cos(i+(0.5*s2)), std::sin(i+(0.5*s2)), -0.6);
      glTexCoord2f((i+(0.5*s2))/(2.0*M_PI), 0.2);
      glVertex3f(r1*std::cos(i+(0.5*s2)), r1*std::sin(i+(0.5*s2)), h2);
    }
  glEnd();
  
  // lower rounded edge
  glBegin(GL_TRIANGLE_STRIP);
    for (double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      const double x1 = r1*std::cos(i);
      const double y1 = r1*std::sin(i);
      const double x2 = r2*std::cos(i+(0.5*s2));
      const double y2 = r2*std::sin(i+(0.5*s2));
      glNormal3f(x1, y1, -0.8);
      glTexCoord2f(i/(2.0*M_PI), 0.2);
      glVertex3f(x1, y1, h2);
      
      glNormal3f(x1, y1, -0.6);
      glTexCoord2f((i+(0.5*s2))/(2.0*M_PI), 0.0);
      glVertex3f(x2, y2, 0.0);
    }
  glEnd();

  // upper rounded edge
  glBegin(GL_TRIANGLE_STRIP);
    for (double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      const double x1 = r2*std::cos(i);
      const double y1 = r2*std::sin(i);
      const double x2 = r1*std::cos(i+(0.5*s2));
      const double y2 = r1*std::sin(i+(0.5*s2));
      glNormal3f(x1, y1, 0.8);
      glTexCoord2f(i/(2.0*M_PI), 1.0);
      glVertex3f(x1, y1, h1+h2+h2);
      
      glNormal3f(x1, y1, 0.6);
      glTexCoord2f((i+(0.5*s2))/(2.0*M_PI), 0.8);
      glVertex3f(x2, y2, h1+h2);
    }
  glEnd();

  glDisable(GL_TEXTURE_2D);
  
  // top
  switch (stone->color())
  {
  case color_red:
    glMaterialColor(1.0, 0.0, 0.0);
    break;
  
  case color_blue:
    glMaterialColor(0.0, 0.0, 1.0);
    break;
  
  default:
    assert(false);
    break;
  };
  
  glBegin(GL_TRIANGLE_FAN);
    glNormal3f(0.0, 0.0, 1.0); 
    glVertex3f(0.0, 0.0, 0.15);
    for(double i=0.0; i<=2.0*M_PI; i+=s2)
    {
      glVertex3f(r2*std::cos(i), r2*std::sin(i), h1+h2+h2);
    }
  glEnd();
  
  glDisable(GL_DEPTH_TEST);

  //----------------------------------------------------------------------------
  // Handle
  //----------------------------------------------------------------------------
  {
    GLfloat x = 0.02;
    GLfloat y = stone->radius();
    GLfloat z = 0.06;
    // level A
    GLfloat a1[3] = {-x, -x, 0.0};
    GLfloat a2[3] = {x, -x, 0.0};
    GLfloat a3[3] = {x, x, 0.0};
    GLfloat a4[3] = {-x, x, 0.0};
    // level B
    GLfloat b1[3] = {-x, -x, z};
    GLfloat b2[3] = {x, -x, z};
    GLfloat b3[3] = {x, x, z};
    GLfloat b4[3] = {-x, x, z};
    GLfloat b5[3] = {y, -x, z};
    GLfloat b6[3] = {y, x, z};
    // level C
    GLfloat c1[3] = {0.0, 0.0, z+(2.0*x)};
    GLfloat c2[3] = {y-x, 0.0, z+(2.0*x)};
    
    //glRotatef((stone->rotation()/(2*3.1415))*360.0, 0.0, 0.0, 1.0);
    glTranslatef(-0.5*(stone->radius()-x), 0.0, stone->height());
  
    // lower part
    glBegin(GL_QUADS);
      glNormal3f(0.0, -1.0, 0.0);
      glVertex3fv(a1); glVertex3fv(a2); glVertex3fv(b2); glVertex3fv(b1);
      glNormal3f(1.0, 0.0, 0.0);
      glVertex3fv(a2); glVertex3fv(a3); glVertex3fv(b3); glVertex3fv(b2);
      glNormal3f(0.0, 1.0, 0.0);
      glVertex3fv(a3); glVertex3fv(a4); glVertex3fv(b4); glVertex3fv(b3);
      glNormal3f(-1.0, 0.0, 0.0);
      glVertex3fv(a4); glVertex3fv(a1); glVertex3fv(b1); glVertex3fv(b4);
    glEnd();
    
    // upper part
    glBegin(GL_TRIANGLES);
      glNormal3f(0.0, -1.0, 0.0); glVertex3fv(b1);
      glNormal3f(0.0, -1.0, 0.0); glVertex3fv(b5);
      glNormal3f(0.707, 0.0, 0.707); glVertex3fv(c2);
      glNormal3f(0.0, -1.0, 0.0); glVertex3fv(b1);
      glNormal3f(0.707, 0.0, 0.707); glVertex3fv(c2);
      glNormal3f(-0.707, 0.0, 0.707); glVertex3fv(c1);
      
      glNormal3f(0.0, 1.0, 0.0); glVertex3fv(b6);
      glNormal3f(0.0, 1.0, 0.0); glVertex3fv(b4);
      glNormal3f(-0.707, 0.0, 0.707); glVertex3fv(c1);
      glNormal3f(0.0, 1.0, 0.0); glVertex3fv(b6);
      glNormal3f(-0.707, 0.0, 0.707); glVertex3fv(c1);
      glNormal3f(0.707, 0.0, 0.707); glVertex3fv(c2);
      
      glNormal3f(1.0, 0.0, 0.0); glVertex3fv(b5);
      glNormal3f(1.0, 0.0, 0.0); glVertex3fv(b6);
      glNormal3f(0.707, 0.0, 0.707); glVertex3fv(c2);
      
      glNormal3f(-1.0, 0.0, 0.0); glVertex3fv(b4);
      glNormal3f(-1.0, 0.0, 0.0); glVertex3fv(b1);
      glNormal3f(-0.707, 0.0, 0.707); glVertex3fv(c1);
    glEnd();
  }
  
  glPopMatrix();
    
  glDisable(GL_CULL_FACE);
}

void renderer::render_floor( double t, double dt )
{
  glNormal3f(0.0, 0.0, 1.0);
  
  glMaterialColor(0.2, 0.2, 1.0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _floor_texture);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glNormal3f(0.0, 0.0, 1.0); glVertex2f(-15.0, -30.0);
    glTexCoord2f(30.0, 0.0); glNormal3f(0.0, 0.0, 1.0); glVertex2f(15.0, -30.0);
    glTexCoord2f(30.0, 60.0); glNormal3f(0.0, 0.0, 1.0); glVertex2f(15.0, 30.0);
    glTexCoord2f(0.0, 60.0); glNormal3f(0.0, 0.0, 1.0); glVertex2f(-15.0, 30.0);
  glEnd();
  glDisable(GL_TEXTURE_2D);
}

void renderer::render_characters( double t, double dt )
{
  if (_gui->current_game())
  {
    boost::shared_ptr<game_character_controller_t> cc =
      _gui->game_character_controller();
    
    // render red team
    glColor3f(1.0, 0.0, 0.0);
    for (game_character_controller_t::player_iterator_t i=cc->begin_team_a_players();
          i!=cc->end_team_a_players();
          ++i)
    {
      render_character(*i, t, dt);
    }
    
    // render blue team
    glColor3f(0.0, 0.0, 1.0);
    for (game_character_controller_t::player_iterator_t i=cc->begin_team_b_players();
          i!=cc->end_team_b_players();
          ++i)
    {
      render_character(*i, t, dt);
    }
  }
}

void renderer::render_character( boost::shared_ptr<character_t> c, double t, double dt )
{
  glPushMatrix();
  glTranslatef(c->position().x(), c->position().y(), c->position().z());
  glEnable(GL_DEPTH_TEST);
  glBegin(GL_QUADS);
    glVertex3f(-0.25, 0.0, 0.0);
    glVertex3f(0.25, 0.0, 0.0);
    glVertex3f(0.25, 0.0, 1.80);
    glVertex3f(-0.25, 0.0, 1.80);
    glVertex3f(0.0, -0.25, 0.0);
    glVertex3f(0.0, 0.25, 0.0);
    glVertex3f(0.0, 0.25, 1.80);
    glVertex3f(0.0, -0.25, 1.80);
  glEnd();
  glDisable(GL_DEPTH_TEST);
  glPopMatrix();
}

void renderer::render_menu_background( double t, double dt )
{
  glEnable(GL_BLEND);
  
  /* Render borders and background. */
  glColor4f(1.0, 1.0, 1.0, 0.5);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _menuborder_texture);
  glBegin(GL_QUADS);
    double offset = (1.0/100.0)*t;
    double gui_width = _gui->size().x();
    double gui_height = _gui->size().y();
    double tex_width = gui_width / 100.0;
    // upper border
    glTexCoord2f(offset, 0.0); glVertex2f(0.0, gui_height-12.8);
    glTexCoord2f(offset+tex_width, 0.0); glVertex2f(gui_width, gui_height-12.8);
    glTexCoord2f(offset+tex_width, 1.0); glVertex2f(gui_width, gui_height);
    glTexCoord2f(offset, 1.0); glVertex2f(0.0, gui_height);
    // bottom border
    offset *= -1.0;
    glTexCoord2f(offset, 0.0); glVertex2f(0.0, 0.0);
    glTexCoord2f(offset+tex_width, 0.0); glVertex2f(gui_width, 0.0);
    glTexCoord2f(offset+tex_width, 1.0); glVertex2f(gui_width, 12.8);
    glTexCoord2f(offset, 1.0); glVertex2f(0.0, 12.8);
  glEnd();
  glDisable(GL_TEXTURE_2D);
  
  // background
  glColor4f(0.0, 0.0, 0.0, 0.5);
  glBegin(GL_QUADS);
    glVertex2f(0.0, 12.8);
    glVertex2f(gui_width, 12.8);
    glVertex2f(gui_width, gui_height-12.8);
    glVertex2f(0.0, gui_height-12.8);
  glEnd();
  
  glDisable(GL_BLEND);
}

void renderer::render_lower_standard_section( double length, double t, double dt )
{
  glColor3f(1.0, 1.0, 1.0);
  
  // render section base
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _champs_texture);
  glMaterialColor(1.0, 1.0, 1.0);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
    glTexCoord2f(length/5.0, 0.0); glVertex3f(length, 0.0, 0.0);
    glTexCoord2f(length/5.0, 1.0); glVertex3f(length, 0.0, 1.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(0.0, 0.0, 1.0);
  glEnd();
  glDisable(GL_TEXTURE_2D);
  
  // render seatings
  glMaterialColor(0.4, 0.4, 0.4);
  glNormal3f(0.0, -0.707, 0.707);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 0.0, 1.0);
    glVertex3f(length, 0.0, 1.0);
    glVertex3f(length, 6.0, 5.0);
    glVertex3f(0.0, 6.0, 5.0);
  glEnd();
  
  // render VIP box
  glMaterialColor(0.5, 0.5, 0.8);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 6.0, 5.0);
    glVertex3f(length, 6.0, 5.0);
    glVertex3f(length, 6.0, 6.0);
    glVertex3f(0.0, 6.0, 6.0);
  glEnd();
  
  // render crowd
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _crowd_texture);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glMaterialColor(1.0, 1.0, 1.0);
  glBegin(GL_QUADS);
  glNormal3f(0.0, -1.0, 0.0);
  for (int i=9; i>=0; --i)
  {
    double texstart = (1.0/5.0)*(i%3);
    double texend = texstart + ((1.0/5.0)*length*2.0);
    double yoff = 0.25 + (0.5*i);
    double zoff = 1.2 + (0.4*i);
    glTexCoord2f(texstart, 0.0); glVertex3f(0.0, yoff, zoff);
    glTexCoord2f(texend, 0.0); glVertex3f(length, yoff, zoff);
    glTexCoord2f(texend, 1.0); glVertex3f(length, yoff, zoff+1.0);
    glTexCoord2f(texstart, 1.0); glVertex3f(0.0, yoff, zoff+1.0);
  }
  glEnd();
  glDisable(GL_BLEND);
  glDisable(GL_TEXTURE_2D);
  glEnable(GL_DEPTH_TEST);
}

void renderer::render_lower_corner_section( double t, double dt )
{
  // render seatings
  glMaterialColor(0.4, 0.4, 0.4);
  glNormal3f(-0.577, -0.577, 0.577);
  glBegin(GL_TRIANGLES);
    glVertex3f(0.0, 0.0, 1.0);
    glVertex3f(6.0, 0.0, 5.0);
    glVertex3f(0.0, 6.0, 5.0);
  glEnd();
  
  // render VIP box
  glMaterialColor(0.5, 0.5, 0.8);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 6.0, 5.0);
    glVertex3f(6.0, 0.0, 5.0);
    glVertex3f(6.0, 0.0, 6.0);
    glVertex3f(0.0, 6.0, 6.0);
  glEnd();
}

void renderer::render_upper_standard_section( double length, double t, double dt )
{
  glColor3f(1.0, 1.0, 1.0);
  
  // render section base
  glMaterialColor(0.5, 0.5, 0.5);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 5.5, 6.0);
    glVertex3f(length, 5.5, 6.0);
    glVertex3f(length, 5.5, 6.5);
    glVertex3f(0.0, 5.5, 6.5);
  glEnd();
  //glMaterialColor(0.0, 0.0, 0.5*(1.0+std::sin(t)));
  glMaterialColor(0.0, 0.0, 1.0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _curlingborder_texture);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    double offset = 2.0*std::sin(t/2.0);
    glTexCoord2f(offset, 0.0); glVertex3f(0.0, 5.45, 6.0);
    glTexCoord2f(offset+(length/1.2), 0.0); glVertex3f(length, 5.45, 6.0);
    glTexCoord2f(offset+(length/1.2), 1.0); glVertex3f(length, 5.45, 6.5);
    glTexCoord2f(offset, 1.0); glVertex3f(0.0, 5.45, 6.5);
  glEnd();
  glDisable(GL_TEXTURE_2D);
  
  // render seatings
  glMaterialColor(0.4, 0.4, 0.4);
  glNormal3f(0.0, -0.707, 0.707);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 5.5, 6.5);
    glVertex3f(length, 5.5, 6.5);
    glVertex3f(length, 11.5, 10.5);
    glVertex3f(0.0, 11.5, 10.5);
  glEnd();
  
  // render back wall
  glMaterialColor(0.3, 0.3, 0.3);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 11.5, 10.5);
    glVertex3f(length, 11.5, 10.5);
    glVertex3f(length, 11.5, 14.5);
    glVertex3f(0.0, 11.5, 14.5);
  glEnd();
  
  // render crowd
  // need to disable depth test, otherwise blending might fail at edges of crowd
  // haven't really looked into that
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _crowd_texture);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glMaterialColor(1.0, 1.0, 1.0);
  glBegin(GL_QUADS);
  glNormal3f(0.0, -1.0, 0.0);
  for (int i=9; i>=0; --i)
  {
    double texstart = (1.0/5.0)*(i%3);
    double texend = texstart + ((1.0/5.0)*length*2.0);
    double yoff = 5.75 + (0.5*i);
    double zoff = 6.7 + (0.4*i);
    glTexCoord2f(texstart, 0.0); glVertex3f(0.0, yoff, zoff);
    glTexCoord2f(texend, 0.0); glVertex3f(length, yoff, zoff);
    glTexCoord2f(texend, 1.0); glVertex3f(length, yoff, zoff+1.0);
    glTexCoord2f(texstart, 1.0); glVertex3f(0.0, yoff, zoff+1.0);
  }
  glEnd();
  glDisable(GL_BLEND);
  glDisable(GL_TEXTURE_2D);
  glEnable(GL_DEPTH_TEST);
}

void renderer::render_upper_corner_section( double t, double dt )
{
  glColor3f(1.0, 1.0, 1.0);
  
  // render section base
  glMaterialColor(0.5, 0.5, 0.5);
  glNormal3f(-0.707, -0.707, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 5.5, 6.0);
    glVertex3f(5.5, 0.0, 6.0);
    glVertex3f(5.5, 0.0, 6.5);
    glVertex3f(0.0, 5.5, 6.5);
  glEnd();
  
  // render seatings
  glMaterialColor(0.4, 0.4, 0.4);
  glNormal3f(-0.557, -0.557, 0.557);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 5.5, 6.5);
    glVertex3f(5.5, 0.0, 6.5);
    glVertex3f(11.5, 0.0, 10.5);
    glVertex3f(0.0, 11.5, 10.5);
  glEnd();
  
  // render corner floor
  glMaterialColor(0.5, 0.5, 0.5);
  glNormal3f(0.0, 0.0, 1.0);
  glBegin(GL_TRIANGLES);
    glVertex3f(0.0, 11.5, 10.5);
    glVertex3f(11.5, 0.0, 10.5);
    glVertex3f(11.5, 11.5, 10.5);
  glEnd();
  
  // render back wall
  glMaterialColor(0.3, 0.3, 0.3);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 11.5, 10.5);
    glVertex3f(11.5, 11.5, 10.5);
    glVertex3f(11.5, 11.5, 14.5);
    glVertex3f(0.0, 11.5, 14.5);
  glEnd();
  glNormal3f(-1.0, 0.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(11.5, 11.5, 10.5);
    glVertex3f(11.5, 0.0, 10.5);
    glVertex3f(11.5, 0.0, 14.5);
    glVertex3f(11.5, 11.5, 14.5);
  glEnd();
}

void renderer::render_sections( double t, double dt )
{
  glEnable(GL_DEPTH_TEST);
  
  // render north sections
  glPushMatrix();
    glTranslatef(-15.0, 30.0, 0.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
  glPopMatrix();
  
  // render north-east section
  glPushMatrix();
    glTranslatef(15.0, 30.0, 0.0);
    render_lower_corner_section(t, dt);
    render_upper_corner_section(t, dt);
  glPopMatrix();
  
  // render east sections
  glPushMatrix();
    glTranslatef(15.0, 30.0, 0.0);
    glRotatef(-90.0, 0.0, 0.0, 1.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
    glTranslatef(30.0, 0.0, 0.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
  glPopMatrix();
  
  // render south-east section
  glPushMatrix();
    glTranslatef(15.0, -30.0, 0.0);
    glRotatef(-90.0, 0.0, 0.0, 1.0);
    render_lower_corner_section(t, dt);
    render_upper_corner_section(t, dt);
  glPopMatrix();
  
  // render south sections
  glPushMatrix();
    glTranslatef(15.0, -30.0, 0.0);
    glRotatef(-180.0, 0.0, 0.0, 1.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
  glPopMatrix();
  
  // render south-west section
  glPushMatrix();
    glTranslatef(-15.0, -30.0, 0.0);
    glRotatef(180.0, 0.0, 0.0, 1.0);
    render_lower_corner_section(t, dt);
    render_upper_corner_section(t, dt);
  glPopMatrix();
  
  // render west sections
  glPushMatrix();
    glTranslatef(-15.0, -30.0, 0.0);
    glRotatef(90.0, 0.0, 0.0, 1.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
    glTranslatef(30.0, 0.0, 0.0);
    render_lower_standard_section(30.0, t, dt);
    render_upper_standard_section(30.0, t, dt);
  glPopMatrix();
  
  // render north-west section
  glPushMatrix();
    glTranslatef(-15.0, 30.0, 0.0);
    glRotatef(90.0, 0.0, 0.0, 1.0);
    render_lower_corner_section(t, dt);
    render_upper_corner_section(t, dt);
  glPopMatrix();
  
  glDisable(GL_DEPTH_TEST);
}

void renderer::render_section_base( double t, double dt )
{
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, _champs_texture);
  
  glMaterialColor(1.0, 1.0, 1.0);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(7.5, 0.0, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(7.5, 0.0, 1.5);
    glTexCoord2f(0.0, 1.0); glVertex3f(0.0, 0.0, 1.5);
    glTexCoord2f(0.0, 0.0); glVertex3f(7.5, 0.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(15.0, 0.0, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(15.0, 0.0, 1.5);
    glTexCoord2f(0.0, 1.0); glVertex3f(7.5, 0.0, 1.5);
  glEnd();
  
  glDisable(GL_TEXTURE_2D);
  
  // render shadow (not highlight...but the other thingie)
  glDisable(GL_LIGHTING);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBegin(GL_QUADS);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(0.0, -0.2);
    glColor4f(0.0, 0.0, 0.0, 0.0); glVertex2f(15.0, -0.2);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(15.0, 0.0);
    glColor4f(0.0, 0.0, 0.0, 1.0); glVertex2f(0.0, 0.0);
  glEnd();
  glDisable(GL_BLEND);
  glEnable(GL_LIGHTING);
}

void renderer::render_standard_section( double t, double dt, int rows )
{
  const double width = 15.0;
  //const int seats = 20;
  //const double seat_height = 0.45;
  const double offset = 0.4;
  const double depth = 0.8;
  
  glPushMatrix();
  
  for (int i=0; i<rows; ++i)
  {
    glMaterialColor(0.7, 0.7, 0.7);
    glBegin(GL_QUADS);
      // render floor
      glNormal3f(0.0, 0.0, 1.0);
      glVertex3f(0.0, 0.0, 0.0);
      glVertex3f(width, 0.0, 0.0);
      glVertex3f(width, depth, 0.0);
      glVertex3f(0.0, depth, 0.0);
      
      // render side
      glNormal3f(0.0, -1.0, 0.0);
      glVertex3f(0.0, depth, 0.0);
      glVertex3f(width, depth, 0.0);
      glVertex3f(width, depth, offset);
      glVertex3f(0.0, depth, offset);
    glEnd();
    
    // render seats
    glPushMatrix();
    glTranslatef(0.0, 0.0, 0.0);
    render_seats(t, dt, 30);
    glPopMatrix();
    
    glTranslatef(0.0, depth, offset);
  }
  
  glPopMatrix();

  // render fence, just testing
  glMaterialColor(0.2, 0.2, 0.2);
  glNormal3f(0.0, -1.0, 0.0);
  glBegin(GL_QUADS);
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(0.1, 0.0, 0.0);
    glVertex3f(0.1, 0.0, 1.0);
    glVertex3f(0.0, 0.0, 1.0);
    glVertex3f(width-0.1, 0.0, 0.0);
    glVertex3f(width, 0.0, 0.0);
    glVertex3f(width, 0.0, 1.0);
    glVertex3f(width-0.1, 0.0, 1.0);
    glVertex3f(0.0, 0.0, 0.9);
    glVertex3f(width, 0.0, 0.9);
    glVertex3f(width, 0.0, 1.0);
    glVertex3f(0.0, 0.0, 1.0);
  glEnd();
}

void renderer::render_corner_section( double t, double dt, int rows )
{
  //const double seat_height = 0.45;
  const double offset = 0.4;
  const double depth = 0.8;
  
  glPushMatrix();
  
  for (int i=0; i<rows; ++i)
  {
    glMaterialColor(0.7, 0.7, 0.7);
    glBegin(GL_QUADS);
      glNormal3f(0.0, 0.0, 1.0);
      glVertex3f(0.0, i*depth, i*offset);
      glVertex3f(i*depth, 0.0, i*offset);
      glVertex3f((i*depth)+depth, 0.0, i*offset);
      glVertex3f(0.0, (i*depth)+depth, i*offset);
      
      glNormal3f(-0.707, -0.707, 0.0);
      glVertex3f(0.0, (i*depth)+depth, i*offset);
      glVertex3f((i*depth)+depth, 0.0, i*offset);
      glVertex3f((i*depth)+depth, 0.0, (i*offset)+offset);
      glVertex3f(0.0, (i*depth)+depth, (i*offset)+offset);
    glEnd();
  }
  
  glPopMatrix();
}

void renderer::render_bar( double t, double dt, double length )
{
}

void renderer::render_ceiling( double t, double dt )
{
  glColor3f(0.3, 0.3, 0.3);
  glEnable(GL_DEPTH_TEST);
  glNormal3f(0.0, 0.0, -1.0);
  glBegin(GL_QUADS);
    glVertex3f(-26.5, 41.5, 14.5);
    glVertex3f(26.5, 41.5, 14.5);
    glVertex3f(26.5, -41.5, 14.5);
    glVertex3f(-26.5, -41.5, 14.5);
  glEnd();
  glDisable(GL_DEPTH_TEST);
}

void renderer::render_mediacube( double t, double dt )
{
}

void renderer::render_seats( double t, double dt, int n )
{
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBindTexture(GL_TEXTURE_2D, _seata_texture);
  glBegin(GL_QUADS);
    glNormal3f(0.0, 0.0, 1.0);
    glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.45);
    glTexCoord2f(1.0*n, 0.0); glVertex3f(n*0.5, 0.0, 0.45);
    glTexCoord2f(1.0*n, 1.0); glVertex3f(n*0.5, 0.8, 0.45);
    glTexCoord2f(0.0, 1.0); glVertex3f(0.0, 0.8, 0.45);
  glEnd();
  glDisable(GL_BLEND);
  glDisable(GL_TEXTURE_2D);

return;
  static GLfloat a[3*4*30];
  static GLfloat b[3*4*30];
  static bool init = false;
  if (not init)
  {
    double offset = 0.0;
    GLfloat* aa = a;
    GLfloat* bb = b;
    for (int j=0; j<30; ++j)
    {
      *aa++ = -0.2+offset; *aa++ = -0.2; *aa++ = 0.45;
      *aa++ = 0.2+offset; *aa++ = -0.2; *aa++ = 0.45;
      *aa++ = 0.2+offset; *aa++ = 0.19; *aa++ = 0.45;
      *aa++ = -0.2+offset; *aa++ = 0.19; *aa++ = 0.45;
      
      *bb++ = -0.2+offset; *bb++ = 0.19; *bb++ = 0.45;
      *bb++ = 0.2+offset; *bb++ = 0.19; *bb++ = 0.45;
      *bb++ = 0.2+offset; *bb++ = 0.19; *bb++ = 0.85;
      *bb++ = -0.2+offset; *bb++ = 0.19; *bb++ = 0.85;
      
      offset += 0.5;
    }
  }
  
  glEnableClientState(GL_VERTEX_ARRAY);
  glMaterialColor(0.7, 0.2, 0.2);
  glNormal3f(0.0, 0.0, 1.0);
  glVertexPointer(3, GL_FLOAT, 0, a);
  glDrawArrays(GL_QUADS, 0, 4*30);
  glDisableClientState(GL_VERTEX_ARRAY);
}

void renderer::render_seat( double t, double dt )
{
}

void renderer::play_title_music_event()
{
  int result = FMOD_OK;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_music_sound, false, &_fmod_music_channel);
  assert(result == FMOD_OK);
  result = _fmod_music_channel->setVolume(0.2);
  assert(result == FMOD_OK);
}

void renderer::stop_title_music_event()
{
  int result = FMOD_OK;
  result = _fmod_music_channel->stop();
  assert(result == FMOD_OK);
}

void renderer::start_arena_sound_event()
{
  int result = FMOD_OK;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_crowd_background_sound, true, &_fmod_crowd_background_channel);
  assert(result == FMOD_OK);
  result = _fmod_crowd_background_channel->setVolume(0.2f);
  assert(result == FMOD_OK);
  result = _fmod_crowd_background_channel->setPaused(false);
  assert(result == FMOD_OK);
}

void renderer::stop_arena_sound_event()
{
  int result = FMOD_OK;
  if (_fmod_crowd_background_channel != NULL)
  {
    result = _fmod_crowd_background_channel->stop();
    assert(result == FMOD_OK);
  }
}

void renderer::focus_item_event()
{
  int result = FMOD_OK;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_focus_sound, false, NULL);
  assert(result == FMOD_OK);
}

void renderer::select_item_event()
{
  int result = FMOD_OK;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_select_sound, false, NULL);
  assert(result == FMOD_OK);
}

void renderer::stone_stone_collision_event(
  boost::shared_ptr<stone> s1,
  boost::shared_ptr<stone> s2,
  double impact_velocity )
{
  if (impact_velocity < 0.1)
  {
    return;
  }
  
  int result;
  //double volume = 1.0;
  FMOD_VECTOR pos;
  pos.x = (s1->position().x() + s2->position().x()) / 2.0;
  pos.y = (s1->position().y() + s2->position().y()) / 2.0;
  pos.z = 0.0;
  FMOD::Channel* tmp;
  result = _fmod_system->playSound(FMOD_CHANNEL_FREE, _fmod_impact_sound, false, &tmp);
  assert(result == FMOD_OK);
  result = tmp->set3DAttributes(&pos, NULL);
  assert(result == FMOD_OK);
}

void renderer::game_attached_event( boost::shared_ptr<game> g )
{
  boost::shared_ptr<renderer_rink_listener_t> listener(new renderer_rink_listener_t(this));
  g->rink_played()->add_listener(listener);
}

void renderer::game_detached_event( boost::shared_ptr<game> )
{
}

}
